Skip to content

在 ASP.NET 使用 Autofac 實作 DI

TLDR

  • Autofac 是 ASP.NET 生態系中功能強大的依賴注入(DI)套件,支援多種框架整合。
  • 核心註冊方式為 RegisterType<T>().As<I>(),並可透過 RegisterAssemblyTypes 進行大量自動註冊。
  • InstancePerLifetimeScope 是 Web 應用中最常用的生命週期,對應 ASP.NET Core 的 Scoped。
  • 當框架不支援 Constructor Injection(如 Web Form/Web Service)或存在循環依賴時,需使用 PropertiesAutowired 進行屬性注入。
  • 在 MVC/Web API 中,需透過 DependencyResolverDependencyResolver 進行整合,並確保 Controller 被正確註冊。
  • 針對 Web.config 的設定,可透過自定義 Module 封裝 AppSettings 並注入至 Options 類別中,解決型別轉換與單元測試問題。

Autofac 基礎概念與註冊

Autofac 透過 ContainerBuilder 建立容器,並在每個 Request 建立 Lifetime Scope。

型別註冊與自動化

  • 基本註冊:使用 RegisterType<{Instance Type}>().As({Declare Type})
  • 大量註冊:使用 Reflection 掃描 Assembly。
csharp
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
    .Where(x => typeof(IAppService).IsAssignableFrom(x));
  • 自定義建立方法:當需要手動控制物件實例化時使用:
csharp
builder.Register(c => new TypeA(c.Resolve<TypeB>()));

註冊型別對應表

Method描述
As()註冊型別給指定型別使用
AsImplementedInterfaces()註冊給自身實作的 Interface 使用(不含 IDisposable)
AsClosedTypesOf(open)註冊給可分配給開放泛型型別的封閉實例使用
AsSelf()將型別註冊給自身使用

TIP

若未設定 As(),預設為 AsSelf()。若已指定其他介面,則不會自動包含 AsSelf(),需手動補上。

Instance Scope 管理

Instance Scope描述.NET Core 對應
InstancePerDependency每次呼叫產生新 Instance(預設值)Transient
InstancePerLifetimeScope每個 Scope 產生一個 InstanceScoped
SingleInstance整個 Container 共用一個 InstanceSingleton

進階應用:屬性注入與循環依賴

什麼情況下會遇到這個問題:當框架本身不支援 Constructor Injection,或發生類別間互相依賴(循環依賴)時。

csharp
builder.RegisterType<Main>()
    .InstancePerLifetimeScope();
builder.RegisterType<Sub>()
    .InstancePerLifetimeScope()
    .PropertiesAutowired(PropertyWiringOptions.AllowCircularDependencies);

WARNING

  • 循環依賴的型別註冊不可使用 InstancePerDependency()
  • 若無循環依賴需求,請勿傳入 PropertyWiringOptions.AllowCircularDependencies

各框架整合實作

ASP.NET MVC

需安裝 Autofac.Mvc5。在 Global.asax.cs 中註冊 Controller 並設定 DependencyResolver

csharp
builder.RegisterControllers(typeof(MvcApplication).Assembly);
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

ASP.NET Web API

需安裝 Autofac.WebApi2。在 Global.asax.cs 中設定:

csharp
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

Web Form 與 Web Service

由於不支援 Constructor Injection,必須使用 Property Injection。

  • Web Form:透過 Autofac.Integration.Web 模組在 Web.config 設定 PropertyInjectionModule
  • Web Service:需實作 WebServiceBase 並在建構式中手動呼叫 InjectProperties(this)

封裝 AppSettings 注入

為解決 WebConfigurationManager 靜態呼叫與型別轉換問題,建議建立 OptionsModule

csharp
private void RegisterOptions<T>(ContainerBuilder builder) where T : class {
    string optionsName = typeof(T).Name.Replace("Options", "");
    var registrationBuilder = builder.RegisterType<T>().AsSelf().InstancePerLifetimeScope();

    foreach (string key in WebConfigurationManager.AppSettings.AllKeys.Where(x => x.StartsWith(optionsName))) {
        registrationBuilder.WithParameter(new ResolvedParameter(
            (pi, ctx) => pi.Name.Equals(Regex.Replace(key, $@"^{optionsName}:", "", RegexOptions.IgnoreCase), StringComparison.OrdinalIgnoreCase),
            (pi, ctx) => Convert.ChangeType(WebConfigurationManager.AppSettings[key], pi.ParameterType)));
    }
}

異動歷程

    • 初版文件建立。